﻿using System.Collections.Generic;
using System.Linq;
using LibraryHub.Core.Models.User;
using LibraryHub.DataAccess;

namespace LibraryHub.BusinessLogic
{
    public class UsersBl
    {
        #region Fields

        private readonly BooksDa bookDao = new BooksDa();
        private readonly UsersDa userDao = new UsersDa();

        #endregion

        #region List

        public IndexModel ListUsers()
        {
            var users = userDao.GetUsersList();

            var model = new IndexModel();
            model.Users = users;

            return model;
        }

        public IndexModel ListReaders()
        {
            var users = userDao.FindUsersByRole(UserRoleEnum.Reader);

            var model = new IndexModel();
            model.Users = users;

            return model;
        }

        public IndexModel ListLibrarians()
        {
            var users = userDao.FindUsersByRole(UserRoleEnum.Librarian);

            var model = new IndexModel();
            model.Users = users;

            return model;
        }

        #endregion

        #region Create

        public bool CreateReader(UserModel user)
        {
            if (user.Role == UserRoleEnum.Reader)
            {
                return CreateUser(user);
            }
            return false;
        }

        public bool CreateLibrarian(UserModel user)
        {
            if (user.Role == UserRoleEnum.Librarian)
            {
                return CreateUser(user);
            }
            return false;
        }

        private bool CreateUser(UserModel user)
        {
            bool result = userDao.AddUser(user);

            return result;
        }

        #endregion

        #region Find

        #region Single

        public UserModel DebugFindUser(int id)
        {
            return FindUser(id);
        }

        public UserModel FindReader(int id)
        {
            var user = FindUser(id);
            if (user != null && user.Role == UserRoleEnum.Reader)
            {
                return user;
            }
            return null;
        }

        public DetailedUserModel FindReaderDetailed(int id)
        {
            var reader = FindReader(id);
            if (reader == null)
            {
                return null;
            }

            var books = bookDao.FindBooksByUserId(id);

            var model = new DetailedUserModel
                            {
                                Id = reader.Id,
                                Login = reader.Login,
                                Password = reader.Password,
                                FullName = reader.FullName,
                                Role = reader.Role,
                                Books = books
                            };
            return model;
        }

        public UserModel FindLibrarian(int id)
        {
            var user = FindUser(id);
            if (user != null && user.Role == UserRoleEnum.Librarian)
            {
                return user;
            }
            return null;
        }

        private UserModel FindUser(int id)
        {
            var model = userDao.FindUser(id);

            return model;
        }

        #endregion

        #region Multiple

        public FindModel FindReaders(UserModel user)
        {
            // I know finding every user and filtering them not in SQL query is not effective.
            // I'm leaving a room for improvements consciously.
            var model = FindUsers(user);
            model.Users = model.Users.Where(x => x.Role == UserRoleEnum.Reader);

            return model;
        }

        public FindModel FindLibrarians(UserModel user)
        {
            // I know finding every user and filtering them not in SQL query is not effective.
            // I'm leaving a room for improvements consciously.
            var model = FindUsers(user);
            model.Users = model.Users.Where(x => x.Role == UserRoleEnum.Librarian);

            return model;
        }

        /// <summary>
        /// Finds as many users as possible, for every field of 'user' separately.
        /// </summary>
        /// <param name="user">Contains fields to search for.</param>
        /// <returns>List of found UserModels</returns>
        private FindModel FindUsers(UserModel user)
        {
            var users = new List<UserModel>();

            var foundUsers = FindUsersByLogin(user);
            if (foundUsers != null)
            {
                users.AddRange(foundUsers);
            }
            foundUsers = FindUsersByFullName(user);
            if (foundUsers != null)
            {
                users.AddRange(foundUsers);
            }

            var model = new FindModel();
            model.CurrentSearch = user;
            model.Users = users.Distinct(new UserModelIdComparer());

            return model;
        }

        private IEnumerable<UserModel> FindUsersByLogin(UserModel user)
        {
            if (user.Login != string.Empty)
            {
                return userDao.FindUsersByLogin(user.Login);
            }
            return null;
        }

        private IEnumerable<UserModel> FindUsersByFullName(UserModel user)
        {
            if (user.FullName != string.Empty)
            {
                return userDao.FindUsersByFullName(user.FullName);
            }
            return null;
        }

        #endregion

        #endregion

        #region Edit

        public bool EditUser(UserModel user)
        {
            bool result = userDao.EditUser(user);

            return result;
        }

        public bool EditReader(UserModel user)
        {
            var dbUser = FindUser(user.Id);
            if (dbUser != null && dbUser.Role == UserRoleEnum.Reader)
            {
                return EditUser(user);
            }
            return false;
        }

        public bool EditLibrarian(UserModel user)
        {
            var dbUser = FindUser(user.Id);
            if (dbUser != null && dbUser.Role == UserRoleEnum.Librarian)
            {
                return EditUser(user);
            }
            return false;
        }

        #endregion

        #region Delete

        public bool DeleteLibrarian(int id)
        {
            var dbUser = FindUser(id);
            if (dbUser != null && dbUser.Role == UserRoleEnum.Librarian)
            {
                return DeleteUser(id);
            }
            return false;
        }

        public bool DeleteReader(int id)
        {
            var dbUser = FindUser(id);
            if (dbUser != null && dbUser.Role == UserRoleEnum.Reader)
            {
                return DeleteUser(id);
            }
            return false;
        }

        private bool DeleteUser(int id)
        {
            bool result = userDao.DeleteUser(id);

            return result;
        }

        #endregion
    }
}
